Option Strict On
Option Explicit On
Imports System.Runtime.InteropServices

Namespace WinUsbDemo

    '''<summary>
    ''' Project: WinUsb_vb
    ''' 
    ''' ***********************************************************************
    ''' Software License Agreement
    '''
    ''' Licensor grants any person obtaining a copy of this software ("You") 
    ''' a worldwide, royalty-free, non-exclusive license, for the duration of 
    ''' the copyright, free of charge, to store and execute the Software in a 
    ''' computer system and to incorporate the Software or any portion of it 
    ''' in computer programs You write.   
    ''' 
    ''' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    ''' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    ''' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    ''' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    ''' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    ''' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    ''' THE SOFTWARE.
    ''' ***********************************************************************
    ''' 
    ''' Author               Date        Version
    ''' Jan Axelson          6/3/08     1.3
    '''                      8/8/08     1.3.1 Because WinUsb_QueryDeviceInformation appears
    '''                                       unreliable for detecting device speed, I
    '''                                       commented out the call to obtain device speed. 
    '''                      10/1/08    1.4   Upgraded to use .NET Framework 3.5     
	'''                      10/29/08   1.5   Minor edits mainly for 64-bit compatibility
	'''                      11/1/08    1.6   Minor edits  
	'''                      11/9/08    1.7   Minor edits       
    ''' 
    ''' This software was created using Visual Studio 2008 Standard Edition with .NET Framework 3.5.
    ''' 
    ''' Purpose: 
    ''' Demonstrates USB communications using the Microsoft WinUSB driver.
    ''' 
    ''' Requirements:
    ''' Windows XP or later and an attached USB device that uses the WinUSB driver.
    ''' 
    ''' Description:
    ''' Finds an attached device whose INF file contains a specific device interface GUID.
    ''' Enables sending and receiving data via bulk, interrupt, and control transfers.
    ''' 
    ''' Uses RegisterDeviceNotification() and WM_DEVICE_CHANGE messages
    ''' to detect when a device is attached or removed.
    ''' 
    ''' For bulk and interrupt transfers, the application uses a Delegate and the BeginInvoke 
    ''' and EndInvoke methods to read data asynchronously, so the application's main thread 
    ''' doesn't have to wait for the device to return data. A callback routine uses 
    ''' marshaling to send data to the form, whose code runs in a different thread. 
    '''  
    ''' This software, an example INF file, and companion device firmware are available from 
    ''' www.Lvr.com
    ''' 
    ''' Send comments, bug reports, etc. to jan@Lvr.com 
    ''' This application has been tested under Windows XP and Windows Vista.        
    ''' </summary>

    Friend Class frmMain
        Inherits System.Windows.Forms.Form
#Region "Windows Form Designer generated code "
        Public Sub New()
            MyBase.New()

            'This call is required by the Windows Form Designer.
            InitializeComponent()
        End Sub
        'Form overrides dispose to clean up the component list.
        Protected Overloads Overrides Sub Dispose(ByVal Disposing As Boolean)
            If Disposing Then
                If Not components Is Nothing Then
                    components.Dispose()
                End If
            End If
            MyBase.Dispose(Disposing)
        End Sub
        'Required by the Windows Form Designer
        Private components As System.ComponentModel.IContainer
        Public ToolTip1 As System.Windows.Forms.ToolTip
        Public WithEvents cmdSendandReceiveViaBulkTransfers As System.Windows.Forms.Button
        Public WithEvents fraControReadTransfer As System.Windows.Forms.GroupBox
        Public WithEvents txtBulkDataToSend As System.Windows.Forms.TextBox
        Public WithEvents fraBulkTransfer As System.Windows.Forms.GroupBox
        Public WithEvents cboInterruptOutByte1 As System.Windows.Forms.ComboBox
        Public WithEvents cboInterruptOutByte0 As System.Windows.Forms.ComboBox
        Public WithEvents fraInterruptTransfer As System.Windows.Forms.GroupBox
        Public WithEvents lstResults As System.Windows.Forms.ListBox
        'NOTE: The following procedure is required by the Windows Form Designer
        'It can be modified using the Windows Form Designer.
        'Do not modify it using the code editor.
        Friend WithEvents cmdFindDevice As System.Windows.Forms.Button
        Friend WithEvents cmdSendAndReceiveViaInterruptTransfers As System.Windows.Forms.Button
        Public WithEvents fraControlWriteTransfer As System.Windows.Forms.GroupBox
        Friend WithEvents cmdControlWriteTransfer As System.Windows.Forms.Button
        Public WithEvents cboControlWriteByte1 As System.Windows.Forms.ComboBox
        Public WithEvents cboControlWriteByte0 As System.Windows.Forms.ComboBox
        Friend WithEvents cmdControlReadTransfer As System.Windows.Forms.Button
        <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
            Me.components = New System.ComponentModel.Container
            Me.ToolTip1 = New System.Windows.Forms.ToolTip(Me.components)
            Me.fraControReadTransfer = New System.Windows.Forms.GroupBox
            Me.cmdControlReadTransfer = New System.Windows.Forms.Button
            Me.cmdSendandReceiveViaBulkTransfers = New System.Windows.Forms.Button
            Me.fraBulkTransfer = New System.Windows.Forms.GroupBox
            Me.txtBulkDataToSend = New System.Windows.Forms.TextBox
            Me.fraInterruptTransfer = New System.Windows.Forms.GroupBox
            Me.cmdSendAndReceiveViaInterruptTransfers = New System.Windows.Forms.Button
            Me.cboInterruptOutByte1 = New System.Windows.Forms.ComboBox
            Me.cboInterruptOutByte0 = New System.Windows.Forms.ComboBox
            Me.lstResults = New System.Windows.Forms.ListBox
            Me.cmdFindDevice = New System.Windows.Forms.Button
            Me.fraControlWriteTransfer = New System.Windows.Forms.GroupBox
            Me.cboControlWriteByte1 = New System.Windows.Forms.ComboBox
            Me.cboControlWriteByte0 = New System.Windows.Forms.ComboBox
            Me.cmdControlWriteTransfer = New System.Windows.Forms.Button
            Me.fraControReadTransfer.SuspendLayout()
            Me.fraBulkTransfer.SuspendLayout()
            Me.fraInterruptTransfer.SuspendLayout()
            Me.fraControlWriteTransfer.SuspendLayout()
            Me.SuspendLayout()
            '
            'fraControReadTransfer
            '
            Me.fraControReadTransfer.BackColor = System.Drawing.SystemColors.Control
            Me.fraControReadTransfer.Controls.Add(Me.cmdControlReadTransfer)
            Me.fraControReadTransfer.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.fraControReadTransfer.ForeColor = System.Drawing.SystemColors.ControlText
            Me.fraControReadTransfer.Location = New System.Drawing.Point(237, 27)
            Me.fraControReadTransfer.Name = "fraControReadTransfer"
            Me.fraControReadTransfer.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.fraControReadTransfer.Size = New System.Drawing.Size(169, 94)
            Me.fraControReadTransfer.TabIndex = 7
            Me.fraControReadTransfer.TabStop = False
            Me.fraControReadTransfer.Text = "Control Read Transfer"
            '
            'cmdControlReadTransfer
            '
            Me.cmdControlReadTransfer.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.cmdControlReadTransfer.Location = New System.Drawing.Point(49, 28)
            Me.cmdControlReadTransfer.Name = "cmdControlReadTransfer"
            Me.cmdControlReadTransfer.Size = New System.Drawing.Size(71, 36)
            Me.cmdControlReadTransfer.TabIndex = 12
            Me.cmdControlReadTransfer.Text = "Send"
            Me.cmdControlReadTransfer.UseVisualStyleBackColor = True
            '
            'cmdSendandReceiveViaBulkTransfers
            '
            Me.cmdSendandReceiveViaBulkTransfers.BackColor = System.Drawing.SystemColors.Control
            Me.cmdSendandReceiveViaBulkTransfers.Cursor = System.Windows.Forms.Cursors.Default
            Me.cmdSendandReceiveViaBulkTransfers.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.cmdSendandReceiveViaBulkTransfers.ForeColor = System.Drawing.SystemColors.ControlText
            Me.cmdSendandReceiveViaBulkTransfers.Location = New System.Drawing.Point(256, 24)
            Me.cmdSendandReceiveViaBulkTransfers.Name = "cmdSendandReceiveViaBulkTransfers"
            Me.cmdSendandReceiveViaBulkTransfers.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.cmdSendandReceiveViaBulkTransfers.Size = New System.Drawing.Size(71, 36)
            Me.cmdSendandReceiveViaBulkTransfers.TabIndex = 8
            Me.cmdSendandReceiveViaBulkTransfers.Text = "Send"
            Me.cmdSendandReceiveViaBulkTransfers.UseVisualStyleBackColor = False
            '
            'fraBulkTransfer
            '
            Me.fraBulkTransfer.BackColor = System.Drawing.SystemColors.Control
            Me.fraBulkTransfer.Controls.Add(Me.txtBulkDataToSend)
            Me.fraBulkTransfer.Controls.Add(Me.cmdSendandReceiveViaBulkTransfers)
            Me.fraBulkTransfer.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.fraBulkTransfer.ForeColor = System.Drawing.SystemColors.ControlText
            Me.fraBulkTransfer.Location = New System.Drawing.Point(16, 139)
            Me.fraBulkTransfer.Name = "fraBulkTransfer"
            Me.fraBulkTransfer.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.fraBulkTransfer.Size = New System.Drawing.Size(341, 89)
            Me.fraBulkTransfer.TabIndex = 4
            Me.fraBulkTransfer.TabStop = False
            Me.fraBulkTransfer.Text = "Bulk Transfers"
            '
            'txtBulkDataToSend
            '
            Me.txtBulkDataToSend.AcceptsReturn = True
            Me.txtBulkDataToSend.BackColor = System.Drawing.SystemColors.Window
            Me.txtBulkDataToSend.Cursor = System.Windows.Forms.Cursors.IBeam
            Me.txtBulkDataToSend.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.txtBulkDataToSend.ForeColor = System.Drawing.SystemColors.WindowText
            Me.txtBulkDataToSend.Location = New System.Drawing.Point(16, 19)
            Me.txtBulkDataToSend.MaxLength = 0
            Me.txtBulkDataToSend.Multiline = True
            Me.txtBulkDataToSend.Name = "txtBulkDataToSend"
            Me.txtBulkDataToSend.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.txtBulkDataToSend.ScrollBars = System.Windows.Forms.ScrollBars.Both
            Me.txtBulkDataToSend.Size = New System.Drawing.Size(224, 59)
            Me.txtBulkDataToSend.TabIndex = 5
            Me.txtBulkDataToSend.Text = "bulk transfer test data"
            '
            'fraInterruptTransfer
            '
            Me.fraInterruptTransfer.BackColor = System.Drawing.SystemColors.Control
            Me.fraInterruptTransfer.Controls.Add(Me.cmdSendAndReceiveViaInterruptTransfers)
            Me.fraInterruptTransfer.Controls.Add(Me.cboInterruptOutByte1)
            Me.fraInterruptTransfer.Controls.Add(Me.cboInterruptOutByte0)
            Me.fraInterruptTransfer.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.fraInterruptTransfer.ForeColor = System.Drawing.SystemColors.ControlText
            Me.fraInterruptTransfer.Location = New System.Drawing.Point(379, 139)
            Me.fraInterruptTransfer.Name = "fraInterruptTransfer"
            Me.fraInterruptTransfer.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.fraInterruptTransfer.Size = New System.Drawing.Size(180, 89)
            Me.fraInterruptTransfer.TabIndex = 1
            Me.fraInterruptTransfer.TabStop = False
            Me.fraInterruptTransfer.Text = "Interrupt Transfers"
            '
            'cmdSendAndReceiveViaInterruptTransfers
            '
            Me.cmdSendAndReceiveViaInterruptTransfers.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.cmdSendAndReceiveViaInterruptTransfers.Location = New System.Drawing.Point(98, 24)
            Me.cmdSendAndReceiveViaInterruptTransfers.Name = "cmdSendAndReceiveViaInterruptTransfers"
            Me.cmdSendAndReceiveViaInterruptTransfers.Size = New System.Drawing.Size(71, 36)
            Me.cmdSendAndReceiveViaInterruptTransfers.TabIndex = 7
            Me.cmdSendAndReceiveViaInterruptTransfers.Text = "Send"
            Me.cmdSendAndReceiveViaInterruptTransfers.UseVisualStyleBackColor = True
            '
            'cboInterruptOutByte1
            '
            Me.cboInterruptOutByte1.BackColor = System.Drawing.SystemColors.Window
            Me.cboInterruptOutByte1.Cursor = System.Windows.Forms.Cursors.Default
            Me.cboInterruptOutByte1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
            Me.cboInterruptOutByte1.Font = New System.Drawing.Font("Arial", 8.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.cboInterruptOutByte1.ForeColor = System.Drawing.SystemColors.WindowText
            Me.cboInterruptOutByte1.Location = New System.Drawing.Point(8, 56)
            Me.cboInterruptOutByte1.Name = "cboInterruptOutByte1"
            Me.cboInterruptOutByte1.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.cboInterruptOutByte1.Size = New System.Drawing.Size(74, 22)
            Me.cboInterruptOutByte1.TabIndex = 3
            '
            'cboInterruptOutByte0
            '
            Me.cboInterruptOutByte0.BackColor = System.Drawing.SystemColors.Window
            Me.cboInterruptOutByte0.Cursor = System.Windows.Forms.Cursors.Default
            Me.cboInterruptOutByte0.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
            Me.cboInterruptOutByte0.Font = New System.Drawing.Font("Arial", 8.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.cboInterruptOutByte0.ForeColor = System.Drawing.SystemColors.WindowText
            Me.cboInterruptOutByte0.Location = New System.Drawing.Point(8, 24)
            Me.cboInterruptOutByte0.Name = "cboInterruptOutByte0"
            Me.cboInterruptOutByte0.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.cboInterruptOutByte0.Size = New System.Drawing.Size(72, 22)
            Me.cboInterruptOutByte0.TabIndex = 2
            '
            'lstResults
            '
            Me.lstResults.BackColor = System.Drawing.SystemColors.Window
            Me.lstResults.Cursor = System.Windows.Forms.Cursors.Default
            Me.lstResults.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.lstResults.ForeColor = System.Drawing.SystemColors.WindowText
            Me.lstResults.HorizontalScrollbar = True
            Me.lstResults.ItemHeight = 16
            Me.lstResults.Location = New System.Drawing.Point(16, 248)
            Me.lstResults.Name = "lstResults"
            Me.lstResults.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.lstResults.Size = New System.Drawing.Size(543, 196)
            Me.lstResults.TabIndex = 0
            '
            'cmdFindDevice
            '
            Me.cmdFindDevice.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.cmdFindDevice.Location = New System.Drawing.Point(446, 44)
            Me.cmdFindDevice.Name = "cmdFindDevice"
            Me.cmdFindDevice.Size = New System.Drawing.Size(102, 59)
            Me.cmdFindDevice.TabIndex = 11
            Me.cmdFindDevice.Text = "Find My Device"
            '
            'fraControlWriteTransfer
            '
            Me.fraControlWriteTransfer.BackColor = System.Drawing.SystemColors.Control
            Me.fraControlWriteTransfer.Controls.Add(Me.cboControlWriteByte1)
            Me.fraControlWriteTransfer.Controls.Add(Me.cboControlWriteByte0)
            Me.fraControlWriteTransfer.Controls.Add(Me.cmdControlWriteTransfer)
            Me.fraControlWriteTransfer.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.fraControlWriteTransfer.ForeColor = System.Drawing.SystemColors.ControlText
            Me.fraControlWriteTransfer.Location = New System.Drawing.Point(16, 25)
            Me.fraControlWriteTransfer.Name = "fraControlWriteTransfer"
            Me.fraControlWriteTransfer.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.fraControlWriteTransfer.Size = New System.Drawing.Size(193, 96)
            Me.fraControlWriteTransfer.TabIndex = 12
            Me.fraControlWriteTransfer.TabStop = False
            Me.fraControlWriteTransfer.Text = "Control Write Transfer"
            '
            'cboControlWriteByte1
            '
            Me.cboControlWriteByte1.BackColor = System.Drawing.SystemColors.Window
            Me.cboControlWriteByte1.Cursor = System.Windows.Forms.Cursors.Default
            Me.cboControlWriteByte1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
            Me.cboControlWriteByte1.Font = New System.Drawing.Font("Arial", 8.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.cboControlWriteByte1.ForeColor = System.Drawing.SystemColors.WindowText
            Me.cboControlWriteByte1.Location = New System.Drawing.Point(16, 58)
            Me.cboControlWriteByte1.Name = "cboControlWriteByte1"
            Me.cboControlWriteByte1.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.cboControlWriteByte1.Size = New System.Drawing.Size(67, 22)
            Me.cboControlWriteByte1.TabIndex = 15
            '
            'cboControlWriteByte0
            '
            Me.cboControlWriteByte0.BackColor = System.Drawing.SystemColors.Window
            Me.cboControlWriteByte0.Cursor = System.Windows.Forms.Cursors.Default
            Me.cboControlWriteByte0.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
            Me.cboControlWriteByte0.Font = New System.Drawing.Font("Arial", 8.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.cboControlWriteByte0.ForeColor = System.Drawing.SystemColors.WindowText
            Me.cboControlWriteByte0.Location = New System.Drawing.Point(16, 30)
            Me.cboControlWriteByte0.Name = "cboControlWriteByte0"
            Me.cboControlWriteByte0.RightToLeft = System.Windows.Forms.RightToLeft.No
            Me.cboControlWriteByte0.Size = New System.Drawing.Size(67, 22)
            Me.cboControlWriteByte0.TabIndex = 14
            '
            'cmdControlWriteTransfer
            '
            Me.cmdControlWriteTransfer.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.cmdControlWriteTransfer.Location = New System.Drawing.Point(102, 30)
            Me.cmdControlWriteTransfer.Name = "cmdControlWriteTransfer"
            Me.cmdControlWriteTransfer.Size = New System.Drawing.Size(71, 36)
            Me.cmdControlWriteTransfer.TabIndex = 13
            Me.cmdControlWriteTransfer.Text = "Send"
            Me.cmdControlWriteTransfer.UseVisualStyleBackColor = True
            '
            'frmMain
            '
            Me.ClientSize = New System.Drawing.Size(579, 469)
            Me.Controls.Add(Me.fraControlWriteTransfer)
            Me.Controls.Add(Me.cmdFindDevice)
            Me.Controls.Add(Me.fraControReadTransfer)
            Me.Controls.Add(Me.fraBulkTransfer)
            Me.Controls.Add(Me.fraInterruptTransfer)
            Me.Controls.Add(Me.lstResults)
            Me.Font = New System.Drawing.Font("Arial", 8.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
            Me.Location = New System.Drawing.Point(21, 28)
            Me.Name = "frmMain"
            Me.StartPosition = System.Windows.Forms.FormStartPosition.Manual
            Me.Text = "WinUSB Demo"
            Me.fraControReadTransfer.ResumeLayout(False)
            Me.fraBulkTransfer.ResumeLayout(False)
            Me.fraBulkTransfer.PerformLayout()
            Me.fraInterruptTransfer.ResumeLayout(False)
            Me.fraControlWriteTransfer.ResumeLayout(False)
            Me.ResumeLayout(False)

        End Sub
#End Region

        ' This GUID must match the GUID in the device's INF file.
        ' To create a GUID in Visual Studio, click Tools > Create GUID.

        Private Const WINUSB_DEMO_GUID_STRING As String = "{42CA71EC-CE1C-44c2-82DE-87D8D8FF6C1E}"

        Private deviceNotificationHandle As IntPtr
        Private myDeviceDetected As Boolean = False
        Private myDeviceManagement As New DeviceManagement()
        Private myDevicePathName As String = ""
        Private myWinUsbDevice As New WinUsbDevice()

        Friend frmMy As frmMain

        ''' <summary>
        ''' Define a class of delegates with the same parameters as 
        ''' WinUsbDevice.ReadViaBulkTransfer and WinUsbDevice.ReadViaInterruptTransfer.
        ''' Used for asynchronous reads from the device.
        ''' </summary>

		Private Delegate Sub ReadFromDeviceDelegate _
		 (ByVal pipeID As Byte, _
		 ByVal bufferLength As UInt32, _
		 ByRef buffer() As Byte, _
		 ByRef lengthTransferred As UInt32, _
		 ByRef success As Boolean)

        ''' <summary>
        ''' Define a delegate with the same parameters as AccessForm.
        ''' Used in accessing the application's form from a different thread.
        ''' </summary>

		Private Delegate Sub MarshalToForm _
		 (ByVal action As String, _
		 ByVal textToAdd As String)

        ''' <summary>
        ''' Performs various application-specific functions that
        ''' involve accessing the application's form.
        ''' </summary>
        ''' 
        ''' <param name="action"> A string that names the action to perform on the form. </param>
        ''' <param name="formText"> Text to display on the form or an empty string. </param>
        '''
        ''' <remarks>
        ''' In asynchronous calls to WinUsb_ReadPipe, the callback function 
        ''' uses this routine to access the application's form, which runs in 
        ''' a different thread.
        ''' </remarks>
        ''' 
        Private Sub AccessForm(ByVal action As String, ByVal formText As String)

            Try
                ' Select an action to perform on the form:

                Select Case action

                    Case "AddItemToListBox"

                        lstResults.Items.Add(formText)

                    Case "AddItemToTextBox"

                        txtBulkDataToSend.SelectedText = formText & vbCrLf

                    Case "EnableCmdSendandReceiveViaBulkTransfers"

                        cmdSendandReceiveViaBulkTransfers.Enabled = True
                        cmdSendandReceiveViaBulkTransfers.Focus()

                    Case "EnableCmdSendandReceiveViaInterruptTransfers"

                        cmdSendAndReceiveViaInterruptTransfers.Enabled = True
                        cmdSendAndReceiveViaInterruptTransfers.Focus()

                    Case "ScrollToBottomOfListBox"

                        lstResults.SelectedIndex = lstResults.Items.Count - 1

                    Case Else

                End Select

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Display the device's speed in the list box.
        ''' </summary>
        ''' 
        ''' <remarks>
        ''' Precondition: device speed was obtained by calling WinUsb_QueryDeviceInformation
        ''' and stored in myDevInfo. 
        ''' </remarks >

        Private Sub DisplayDeviceSpeed()

            Dim speed As String = ""

            myWinUsbDevice.QueryDeviceSpeed()

            Try
                Select Case myWinUsbDevice.myDevInfo.devicespeed
                    Case 1
                        speed = "low"
                    Case 2
                        speed = "full"
                    Case 3
                        speed = "high"
                End Select

                lstResults.Items.Add("Device speed = " & speed)

            Catch ex As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' If a device with the specified device interface GUID hasn't been previously detected,
        ''' look for it. If found, open a handle to the device.
        ''' </summary>
        ''' 
        ''' <returns>
        ''' True if the device is detected, False if not detected.
        ''' </returns>

        Private Function FindMyDevice() As Boolean

            Dim deviceFound As Boolean
            Dim devicePathName As String = ""
            Dim success As Boolean

            Try

                If Not myDeviceDetected Then

                    ' Convert the device interface GUID string to a GUID object: 

                    Dim winUsbDemoGuid As New System.Guid(WINUSB_DEMO_GUID_STRING)

                    'Fill an array with the device path names of all attached devices with matching GUIDs.

                    deviceFound = myDeviceManagement.FindDeviceFromGuid _
                        (winUsbDemoGuid, _
                        devicePathName)

                    If deviceFound = True Then

                        success = myWinUsbDevice.GetDeviceHandle(devicePathName)

                        If (success) Then

                            lstResults.Items.Add("Device detected:")

                            ScrollToBottomOfListBox()

                            myDeviceDetected = True

                            'Save DevicePathName so OnDeviceChange() knows which name is my device.

                            myDevicePathName = devicePathName

                        Else
                            'There was a problem in retrieving the information.

                            myDeviceDetected = False
                            myWinUsbDevice.CloseDeviceHandle()

                        End If

                    End If

                    If myDeviceDetected Then

                        'The device was detected.
                        'Register to receive notifications if the device is removed or attached.

                        success = myDeviceManagement.RegisterForDeviceNotifications _
                            (myDevicePathName, _
                            frmMy.Handle, _
                            winUsbDemoGuid, _
                            deviceNotificationHandle)

                        If success Then

                            myWinUsbDevice.InitializeDevice()

                            ' Commented out due to unreliable response from WinUsb_QueryDeviceInformation.
							' DisplayDeviceSpeed()

                        End If

                    Else
                        lstResults.Items.Add("Device not found.")
                        cmdSendandReceiveViaBulkTransfers.Enabled = True
                        cmdSendAndReceiveViaInterruptTransfers.Enabled = True

                    End If

                Else
                    lstResults.Items.Add("Device detected.")
                End If

                ScrollToBottomOfListBox()

                Return myDeviceDetected

            Catch ex As Exception
                Throw
            End Try

        End Function

        ''' <summary>
        ''' Retrieves received data from a bulk endpoint.
        ''' This routine is called automatically when myWinUsbDevice.ReadViaBulkTransfer
        ''' returns. The routine calls several marshaling routines to access the main form.
        ''' </summary>
        ''' 
        ''' <param name="ar"> An object containing status information about the 
        ''' asynchronous operation.</param>
        ''' 
        Private Sub GetReceivedBulkData(ByVal ar As IAsyncResult)

            Dim bytesRead As UInt32
            Dim myEncoder As New System.Text.ASCIIEncoding
            Dim receivedDataBuffer As Byte()
            Dim receivedtext As String = ""
            Dim success As Boolean

            Try
                receivedDataBuffer = Nothing

                'Define a delegate using the IAsyncResult object.

                Dim deleg As ReadFromDeviceDelegate = _
                    DirectCast(ar.AsyncState, ReadFromDeviceDelegate)

                'Get the IAsyncResult object and the values of other paramaters that the
                'BeginInvoke method passed ByRef.

                deleg.EndInvoke(receivedDataBuffer, bytesRead, success, ar)

                'Display the received data in the form's list box.

                If (ar.IsCompleted And success) Then

                    MyMarshalToForm("AddItemToListBox", "Data received via bulk transfer:")

                    ' Convert the received bytes to a string for display.

                    receivedtext = myEncoder.GetString(receivedDataBuffer)

                    MyMarshalToForm("AddItemToListBox", receivedtext)

                Else

                    MyMarshalToForm("AddItemToListBox", "The attempt to read bulk data has failed.")

                    myDeviceDetected = False

                End If

                MyMarshalToForm("ScrollToBottomOfListBox", "")

                'Enable requesting another transfer.

                MyMarshalToForm("EnableCmdSendandReceiveViaBulkTransfers", "")

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Retrieves received data from an interrupt endpoint.
        ''' This routine is called automatically when myWinUsbDevice.ReadViaInterruptTransfer
        ''' returns. The routine calls several marshaling routines to access the main form.
        ''' </summary>
        ''' 
        ''' <param name="ar"> An object containing status information about the 
        ''' asynchronous operation.</param>

        Private Sub GetReceivedInterruptData(ByVal ar As IAsyncResult)

            Dim byteValue As String = ""
            Dim bytesRead As UInt32
            Dim receivedDataBuffer As Byte()
            Dim success As Boolean

            Try
                receivedDataBuffer = Nothing

                'Define a delegate using the IAsyncResult object.

                Dim deleg As ReadFromDeviceDelegate = _
                    DirectCast(ar.AsyncState, ReadFromDeviceDelegate)

                'Get the IAsyncResult object and the values of other paramaters that the
                'BeginInvoke method passed ByRef.

                deleg.EndInvoke(receivedDataBuffer, bytesRead, success, ar)

                'Display the received data in the form's list box.

                If (ar.IsCompleted And success) Then

                    MyMarshalToForm("AddItemToListBox", "Data received via interrupt transfer:")

                    MyMarshalToForm("AddItemToListBox", " Received Data:")

                    For i As Int32 = 0 To receivedDataBuffer.GetUpperBound(0)

                        ' Convert the byte value to a 2-character hex string.

                        byteValue = String.Format("{0:X2} ", receivedDataBuffer(i))

                        MyMarshalToForm("AddItemToListBox", " " & byteValue)

                    Next i

                Else

                    MyMarshalToForm("AddItemToListBox", "The attempt to read interrupt data has failed.")

                    myDeviceDetected = False

                End If

                MyMarshalToForm("ScrollToBottomOfListBox", "")

                'Enable requesting another transfer.

                MyMarshalToForm("EnableCmdSendandReceiveViaInterruptTransfers", "")

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Initializes elements on the form.
        ''' </summary>

        Private Sub InitializeDisplay()

            Dim byteValue As String = ""

            Try

                'Create dropdown list boxes.

                For i As Int16 = 0 To 255

                    byteValue = String.Format("{0:X2} ", i)

                    frmMy.cboInterruptOutByte0.Items.Insert(i, byteValue)
                    frmMy.cboInterruptOutByte1.Items.Insert(i, byteValue)
                    frmMy.cboControlWriteByte0.Items.Insert(i, byteValue)
                    frmMy.cboControlWriteByte1.Items.Insert(i, byteValue)

                Next i

                'Select a default value for each box

                frmMy.cboInterruptOutByte0.SelectedIndex = 0
                frmMy.cboInterruptOutByte1.SelectedIndex = 128
                frmMy.cboControlWriteByte0.SelectedIndex = 65
                frmMy.cboControlWriteByte1.SelectedIndex = 53

                If Not (myWinUsbDevice.IsWindowsXpOrLater()) Then

                    lstResults.Items.Add("The operating system is not Windows XP or later.")
                    lstResults.Items.Add("The WinUsb driver requires Windows XP or later.")

                End If

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Initiates a Control Read transfer. (Data stage is device to host.)
        ''' </summary>
        ''' 
        Private Sub InitiateControlInTransfer()

            Dim formText As String = ""
            Dim dataStage(1) As Byte
            Dim success As Boolean

            Try
                'If the device hasn't been detected, was removed, or timed out on a previous attempt
                'to access it, look for the device.

                myDeviceDetected = FindMyDevice()

                If myDeviceDetected Then

                    success = myWinUsbDevice.Do_Control_Read_Transfer(dataStage)

                    If success Then

                        formText = "Bytes received via Control Read transfer:"
                        AccessForm("AddItemToListBox", formText)

                        For i As Int32 = 0 To dataStage.Length - 1
                            formText = String.Format("{0:X2} ", dataStage(i))
                            AccessForm("AddItemToListBox", formText)
                        Next i

                    Else
                        formText = "Control Read transfer failed."
                        AccessForm("AddItemToListBox", formText)
                        myDeviceDetected = False
                    End If
                End If

                ScrollToBottomOfListBox()

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Initiates a Control Write transfer. (Data stage is host to device.)
        ''' </summary>
        ''' 
        Private Sub InitiateControlOutTransfer()

            Dim comboBoxText As String = ""
            Dim dataStage(1) As Byte
            Dim formText As String = ""
            Dim success As Boolean

            Try
                'If the device hasn't been detected, was removed, or timed out on a previous attempt
                'to access it, look for the device.

                myDeviceDetected = FindMyDevice()

                If myDeviceDetected Then

                    ' Get the value to send as a hex string.

                    comboBoxText = _
                        System.Convert.ToString(cboControlWriteByte0.SelectedItem).TrimEnd(Nothing)

                    ' Convert the string to a byte.

                    dataStage(0) = _
                            Convert.ToByte(String.Format("{0:X2}", comboBoxText), 16)

                    ' Get the value to send as a hex string.

                    comboBoxText = _
                        System.Convert.ToString(cboControlWriteByte1.SelectedItem).TrimEnd(Nothing)

                    ' Convert the string to a byte.

                    dataStage(1) = _
                            Convert.ToByte(String.Format("{0:X2}", comboBoxText), 16)

                    success = myWinUsbDevice.Do_Control_Write_Transfer(dataStage)

                    If success Then
                        formText = "Control Write transfer completed successfully."
                    Else
                        formText = "Control Write transfer failed."
                        myDeviceDetected = False
                    End If

                    AccessForm("AddItemToListBox", formText)
                End If

                ScrollToBottomOfListBox()
               
            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Enables accessing a form from another thread 
        ''' </summary>
        ''' 
        ''' <param name="action"> A string that names the action to perform on the form. </param>
        ''' <param name="textToDisplay"> Text that the form displays or uses for 
        ''' another purpose. Actions that don't use text ignore this parameter. </param>

		Private Sub MyMarshalToForm _
		 (ByVal action As String, _
		 ByVal textToDisplay As String)

			Dim args() As Object = {action, textToDisplay}
			Dim MarshalToFormDelegate As MarshalToForm

			Try
				' The AccessForm routine contains the code that accesses the form.

				MarshalToFormDelegate = New MarshalToForm(AddressOf AccessForm)

				' Execute AccessForm, passing the parameters in args.

				MyBase.Invoke(MarshalToFormDelegate, args)

			Catch ex As Exception
				Throw
			End Try

		End Sub

        ''' <summary>
        ''' Called when a WM_DEVICECHANGE message has arrived,
        ''' indicating that a device has been attached or removed.
        ''' </summary>
        ''' 
        ''' <param name="m"> A message with information about the device. </param>

        Friend Sub OnDeviceChange(ByVal m As Message)

            Try
                If (m.WParam.ToInt32 = DeviceManagement.DBT_DEVICEARRIVAL) Then

                    ' If WParam contains DBT_DEVICEARRIVAL, a device has been attached.
                    ' Find out if it's the device we're communicating with.

                    If myDeviceManagement.DeviceNameMatch(m, myDevicePathName) Then
                        lstResults.Items.Add("My device attached.")
                    End If

                ElseIf (m.WParam.ToInt32 = DeviceManagement.DBT_DEVICEREMOVECOMPLETE) Then

                    ' If WParam contains DBT_DEVICEREMOVAL, a device has been removed.
                    ' Find out if it's the device we're communicating with.

                    If myDeviceManagement.DeviceNameMatch(m, myDevicePathName) Then

                        lstResults.Items.Add("My device removed.")

                        ' Set MyDeviceDetected False so on the next data-transfer attempt,
                        ' FindMyDevice() will be called to look for the device 
                        ' and get a new handle.

                        frmMy.myDeviceDetected = False

                    End If
                End If

                ScrollToBottomOfListBox()

            Catch ex As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' Initiates a read operation from a bulk IN endpoint.
        ''' To enable reading without blocking the main thread, uses an asynchronous delegate.
        ''' </summary>
        ''' 
        ''' <remarks>
        ''' To enable reading more than 64 bytes (with device firmware support), increase bytesToRead.
        ''' </remarks> 

        Private Sub ReadDataViaBulkTransfer()

            Dim ar As IAsyncResult
            Dim buffer(63) As Byte
            Dim bytesRead As UInt32
            Dim bytesToRead As UInt32 = 64
            Dim success As Boolean

            ' Define a delegate for the ReadViaBulkTransfer method of WinUsbDevice.

            Dim MyReadFromDeviceDelegate As _
                New ReadFromDeviceDelegate(AddressOf myWinUsbDevice.ReadViaBulkTransfer)

            Try

                ' The BeginInvoke method calls MyWinUsbDevice.ReadViaBulkTransfer to attempt 
                ' to read data. The method has the same parameters as ReadViaBulkTransfer,
                ' plus two additional parameters:
                ' GetReceivedBulkData is the callback routine that executes when 
                ' ReadViaBulkTransfer returns.
                ' MyReadFromDeviceDelegate is the asynchronous delegate object.

                ar = MyReadFromDeviceDelegate.BeginInvoke _
                    (myWinUsbDevice.myDevInfo.bulkInPipe, _
                    bytesToRead, _
                    buffer, _
                    bytesRead, _
                    success, _
                    New AsyncCallback(AddressOf GetReceivedBulkData), _
                    MyReadFromDeviceDelegate)

            Catch ex As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' Initiates a read operation from an interrupt IN endpoint.
        ''' To enable reading without blocking the main thread, uses an asynchronous delegate.
        ''' </summary>
        ''' 
        ''' <remarks>
        ''' To enable reading more than 2 bytes (with device firmware support), increase bytesToRead.
        ''' </remarks>

        Private Sub ReadDataViaInterruptTransfer()

            Dim ar As IAsyncResult
            Dim buffer(1) As Byte
            Dim bytesRead As UInt32
            Dim bytesToRead As UInt32 = 2
            Dim success As Boolean

            Try
                ' Define a delegate for the ReadViaInterruptTransfer method of WinUsbDevice.

                Dim MyReadFromDeviceDelegate As _
                    New ReadFromDeviceDelegate(AddressOf myWinUsbDevice.ReadViaInterruptTransfer)

                ' The BeginInvoke method calls MyWinUsbDevice.ReadViaInterruptTransfer to attempt 
                ' to read data. The method has the same parameters as ReadViaInterruptTransfer,
                ' plus two additional parameters:
                ' GetReceivedInterruptData is the callback routine that executes when 
                ' ReadViaInterruptTransfer returns.
                ' MyReadFromDeviceDelegate is the asynchronous delegate object.

				ar = MyReadFromDeviceDelegate.BeginInvoke _
				 (myWinUsbDevice.myDevInfo.interruptInPipe, _
				 bytesToRead, _
				 buffer, _
				 bytesRead, _
				 success, _
				 New AsyncCallback(AddressOf GetReceivedInterruptData), _
				 MyReadFromDeviceDelegate)

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Scroll to the bottom of the list box and trim if needed.
        ''' </summary>

        Private Sub ScrollToBottomOfListBox()

            Try
                lstResults.SelectedIndex = lstResults.Items.Count - 1

                'If the list box is getting too large, trim its contents.

                If lstResults.Items.Count > 1000 Then

                    For i As Int32 = 1 To 800
                        lstResults.Items.RemoveAt(i)
                    Next i

                End If

            Catch ex As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' Initiates sending data via a bulk transfer, then receiving data via a bulk transfer.
        ''' </summary>

        Private Sub SendAndReceiveViaBulkTransfers()

            Try
                Dim bytesToSend As UInt32
                Dim dataToSend As String = ""
                Dim databuffer() As Byte
                Dim formText As String = ""
                Dim myEncoder As New System.Text.ASCIIEncoding()
                Dim success As Boolean

                ' Get data to send from the textbox.

                dataToSend = txtBulkDataToSend.Text

                ' Convert the string to a byte array.

                databuffer = myEncoder.GetBytes(dataToSend)
                bytesToSend = Convert.ToUInt32(databuffer.Length)

                'If the device hasn't been detected, was removed, or timed out on a previous attempt
                'to access it, look for the device.

                myDeviceDetected = FindMyDevice()

                If myDeviceDetected Then

                    success = myWinUsbDevice.SendViaBulkTransfer(databuffer, bytesToSend)

                    If success Then
                        formText = "Data sent via bulk transfer."
                    Else
                        formText = "Bulk OUT transfer failed."

                    End If

                    AccessForm("AddItemToListBox", formText)

                    ReadDataViaBulkTransfer()

                End If

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Initiates sending data via an interrupt transfer, then retrieving data 
        ''' via an interrupt transfer.
        ''' </summary>

        Private Sub SendAndReceiveViaInterruptTransfers()

            Dim bytesToSend As UInt32 ' winusb_readpipe requires this parameter to be a UINT32.
            Dim comboBoxText As String = ""
            Dim dataBuffer(1) As Byte
            Dim formText As String = ""
            Dim success As Boolean

            Try
                ' Get bytes to send from comboboxes.

                ' Get the value to send as a hex string.

                comboBoxText = _
                    System.Convert.ToString(cboInterruptOutByte0.SelectedItem).TrimEnd(Nothing)

                ' Convert the string to a byte.

                dataBuffer(0) = _
                        Convert.ToByte(String.Format("{0:X2}", comboBoxText), 16)

                ' Get the value to send as a hex string.

                comboBoxText = _
                    System.Convert.ToString(cboInterruptOutByte1.SelectedItem).TrimEnd(Nothing)

                ' Convert the string to a byte.

                dataBuffer(1) = _
                        Convert.ToByte(String.Format("{0:X2}", comboBoxText), 16)

                bytesToSend = Convert.ToUInt32(dataBuffer.Length)

                'If the device hasn't been detected, was removed, or timed out on a previous attempt
                'to access it, look for the device.

                myDeviceDetected = FindMyDevice()

                If myDeviceDetected Then

                    success = myWinUsbDevice.SendViaInterruptTransfer(dataBuffer, bytesToSend)

                    If success Then
                        formText = "Data sent via interrupt transfer."
                    Else
                        formText = "Interrupt OUT transfer failed."
                    End If

                    AccessForm("AddItemToListBox", formText)

                    ReadDataViaInterruptTransfer()

                End If

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Perform actions that must execute when the program ends.
        ''' </summary>

        Private Sub Shutdown()

            Try
                myWinUsbDevice.CloseDeviceHandle()

                myDeviceManagement.StopReceivingDeviceNotifications(deviceNotificationHandle)

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Perform actions that must execute when the program starts.
        ''' </summary>

        Private Sub Startup()

            Try
                myWinUsbDevice = New WinUsbDevice()
                InitializeDisplay()

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Calls a routine to initiate a Control Read transfer. (Data stage is device to host.)
        ''' </summary>

        Private Sub cmdControlReadTransfer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdControlReadTransfer.Click

            InitiateControlInTransfer()
        End Sub

        ''' <summary>
        ''' Calls a routine to initiate a Control Write transfer. (Data stage is host to device.)
        ''' </summary>
        '''  
        Private Sub cmdControlWriteTransfer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdControlWriteTransfer.Click

            InitiateControlOutTransfer()

        End Sub

        ''' <summary>
        ''' Search for a specific device.
        ''' </summary>

        Private Sub cmdFindDevice_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdFindDevice.Click

            Try
                FindMyDevice()

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Calls a routine to exchange data via bulk transfers.
        ''' </summary>

        Private Sub cmdSendAndReceiveViaBulkTransfers_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles cmdSendandReceiveViaBulkTransfers.Click

            Try
                'Don't allow another transfer request until this one completes.

                cmdSendandReceiveViaBulkTransfers.Enabled = False

                SendAndReceiveViaBulkTransfers()

            Catch ex As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' Calls a routine to exchange data via interrupt transfers.
        ''' </summary>
        ''' 
        Private Sub cmdSendAndReceiveViaInterruptTransfers_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSendAndReceiveViaInterruptTransfers.Click

            Try
                'Don't allow another transfer request until this one completes.

                cmdSendAndReceiveViaInterruptTransfers.Enabled = False

                SendAndReceiveViaInterruptTransfers()

            Catch ex As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' Perform shutdown operations.
        ''' </summary>

        Private Sub frmMain_Closed(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Closed

            Try
                Shutdown()

            Catch ex As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' Perform startup operations.
        ''' </summary>

        Private Sub frmMain_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load

            Try
				frmMy = Me
                Startup()

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' Overrides WndProc to enable checking for and handling
        ''' WM_DEVICECHANGE messages.
        ''' </summary>
        ''' 
        ''' <param name="m"> A Windows message.
        ''' </param> 
        ''' 
        Protected Overrides Sub WndProc(ByRef m As Message)

            Try
                'The OnDeviceChange routine processes WM_DEVICECHANGE messages.

                If m.Msg = DeviceManagement.WM_DEVICECHANGE Then
                    OnDeviceChange(m)
                End If

                'Let the base form process the message.

                MyBase.WndProc(m)

            Catch ex As Exception
                Throw
            End Try

        End Sub

    End Class

End Namespace

